/*
 * Copyright(c) 2024 长沙市希尚网络科技有限公司
 * 注意：本内容仅限于长沙市希尚网络科技有限公司内部传阅，禁止外泄以及用于其他的商业目的
 */

package org.ssssssss.example.provider;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.ssssssss.example.utils.TraceUtils;

/**
 * TODO
 *
 * @author liuy
 * @version 1.0 2024/7/30 0030
 */
@Data
@ApiModel(description = "返回结果")
@Slf4j
public class ResultHolder<T> implements java.io.Serializable {

    private static final long serialVersionUID = 9043010987931787261L;

    private static final String KEY_CODE = "code";
    private static final String KEY_MESSAGE = "message";
    private static final Integer SUCCESS_CODE = 0;
    private static final String SUCCESS_MESSAGE = "操作成功";
    private static final String FAILURE_MESSAGE = "操作失败";

    /**
     * 返回码
     */
    @ApiModelProperty(value = "返回码, 0-成功 其它-失败", example = "0")
    private Integer code;

    /**
     * 消息
     */
    @ApiModelProperty(value = "错误信息")
    private String message;

    /**
     * 上下文信息
     */
    @ApiModelProperty(value = "上下文信息")
    private String description;

    @ApiModelProperty(value = "日志链路id")
    private String traceId;

    /**
     * 内容
     */
    @ApiModelProperty(value = "返回内容，成功时可能没有body")
    private T body;


    @ApiModelProperty(value = "返回统计，对body内容的总结")
    private Object summary;

    /**
     * 时间戳
     */
    @ApiModelProperty(value = "服务器时间戳")
    private Integer timestamp;

    @ApiModelProperty(value = "重定向地址")
    private String redirect;

    private Object links;

    /**
     * jackson 反序列化调用默认构造器
     */
    public ResultHolder() {
    }

    public ResultHolder(Integer code, String message, T body, String description) {
        this.code = code;
        this.message = message;
        this.body = body;
        this.description = description;
        this.timestamp = (int) (System.currentTimeMillis() / 1000);
        this.traceId = TraceUtils.getTraceId();
        if (0 != code) {
            log.error("Result error: {}", this);
        } else {
            if (log.isTraceEnabled()) {
                log.trace("Result body: {}", body);
            }
        }
    }

    public ResultHolder(Integer status, String message) {
        this(status, message, null, null);
    }

    public ResultHolder(T body) {
        this(SUCCESS_CODE, SUCCESS_MESSAGE, body, null);
    }

    public static <T> ResultHolder<T> create(T body, boolean isSuccess, Integer errorCode) {
        if (isSuccess) {
            return new ResultHolder<>(SUCCESS_CODE, SUCCESS_MESSAGE, body, null);
        } else {
            return new ResultHolder<>(errorCode, FAILURE_MESSAGE, body, null);
        }
    }

    public static <P> ResultHolder<P> error(Integer error, String message) {
        return new ResultHolder<>(error, message);
    }

    public static <P> ResultHolder<P> error(Integer error, String message, String extra) {
        return new ResultHolder<>(error, message, null, extra);
    }

    public static <T> ResultHolder<T> success(T body) {
        return new ResultHolder<>(body);
    }

    public ResultHolder<T> body(T body) {
        this.setBody(body);
        return this;
    }

    public ResultHolder<T> code(Integer code) {
        this.setCode(code);
        return this;
    }

    public ResultHolder<T> message(String message) {
        this.setMessage(message);
        return this;
    }

    public ResultHolder<T> description(String description) {
        this.setDescription(description);
        return this;
    }

    /**
     * 判断是否成功
     *
     * @return 判断是否成功
     */
    public boolean success() {
        return SUCCESS_CODE.equals(this.getCode());
    }

    public boolean isSuccess() {
        return this.success();
    }


    /**
     * 链式操作支持
     *
     * @param func Lambda
     * @return Optional
     */
    public <R> Optional<R> map(Function<T, R> func) {
        if (!this.success()) {
            log.error("{} {} {}", this.code, this.message, this.description);
        }
        return Optional.ofNullable(body).filter(bd -> this.success()).map(func);
    }

    public void peek(Consumer<T> consumer) {
        Optional.ofNullable(body).filter(bd -> this.success()).ifPresent(consumer);
    }




}
